#include<stdio.h>
/*
前言
    学生信息  ：姓名  学号  年龄  成绩  出生年月日  这些数据都不是同一个类型的
    引入结构体  
    自定义数据类型：
声明一个结构体类型
    struct 结构体类型名
    {
        成员列表；
    }；
    例如：
        struct student
        {
            char name[20];//姓名
            int age;//年龄
            double socre[5];//成绩
        };
定义一个结构体类型变量  ： 数据类型  变量名;
                    例如：struct student a;//定义一个变量 
                    struct student c={"zhangsan",18,{89,99,90,99,88}};//初始化赋值
                    struct student d={.age=18,.name="lisi",.socre[0]=99,.socre[1]=88,.socre[2]=90,.socre[3]=100,.socre[4]=78};//可以不用按顺序去进行赋值
     还可以在声明数据类型时就定义变量
                例如：
                     struct student
                    {
                        char name[20];//姓名
                        int age;//年龄
                        double socre[5];//成绩
                    }b;//声明一个结构体类型的同时 定义了一个变量b
定义一个结构体数组：数据类型  数组名[数组长度];
                     struct student num[3]={{.name="zhangsan"},{.name="lisi",.age=18},{.name="wangwu",.age=20}};
结构体的应用（成员访问）：变量名.成员       .:成员访问运算符
对结构体类型进行重命名操作
                typedef struct student
                    {
                        char name[20];//姓名
                        int age;//年龄
                        double socre[5];//成绩
                    }stu,zs;//!!!!这里的stu不是变量 不能初始化赋值  这里的zs也是别名
                //将声明一个结构体类型struct student，并取别名为 stu,所以stu可以作为结构体类型来使用   :stu a;
                在学习数据结构时 会见到如下声明  
                 typedef struct student
                 {
                 int a;
                 }stu,*p_stu;  
                 //等价于声明了一个 struct student类型  并将其取别名为stu   ,另外将struct student * 取别名为p_stu,所以p_stu是一个结构体指针类型

结构体指针：
        struct student *p;//结构体指针
        stu *p；//结构体指针  前提是 有 typedef struct student stu;操作
        p_stu p;//结构体指针  前提是 有 typedef struct student *p_stu;操作
        指针如何访问成员 ：
                    方法1： （*p）.成员      （.:直接访问运算符）
                    方法2： p->成员          （->:间接访问运算符）
结构体类型所占空间大小
                字节对齐
结构体套结构体是允许的


*/


struct student
{
    char name[20];//姓名
    int age;//年龄b
    double socre[5];//成绩
}b={"b",18,{89,99,90,99,88}};//声明一个结构体类型的同时 定义了一个变量b 需要按照成员的顺序去进行赋值
typedef struct student stu;//将结构体类型 取别名为stu
typedef struct student *p_stu;//将struct student *取别名为p_stu  因此p_stu就是一个结构体指针类型
//结构体变量的访问
void struct_1(void);
//结构体数组的应用
void struct_num_2(void);
//打印数组的数据
void show_data(stu arr[]);
//通过指针的方式来输出 数据
void show_data_bypointer(p_stu p);
//结构体空间的大小以及地址打印输出
void struct_addr_size(void);
//结构体套结构体
void struct_qiantao(void);
int main(int argc, char const *argv[])
{ 
    //struct_1();
  // struct_num_2();
 // struct_addr_size();
 struct_qiantao();
    return 0;
}

//结构体套结构体
void struct_qiantao(void)
{
    typedef struct birth//
    {
        int Y;//年
        int M;//月
        int D;//日
    }birth;
    typedef struct people
    {
        char name[20];
        char sex;//w:女  m：男
        birth birthday;//结构体变量  是可以嵌套定义另外一个结构体变量的  结构体套结构体声明是不允许的
        
    }PEOPLE;
    PEOPLE zs={.name="zhangsan",.sex='m',.birthday.Y=2002,.birthday.M=6,.birthday.D=15};
    printf("name:%s\n sex:%c\n year:%d month:%d day:%d\n",zs.name,zs.sex,zs.birthday.Y,zs.birthday.M,zs.birthday.D);
}









//结构体空间的大小以及地址打印输出
void struct_addr_size(void)
{
    struct test
    {
        char name[101];//姓名
        double sex;
        // int age;//年龄b
        //  double socre[5];//成绩
 
    }temp;
    //printf("&temp:%p &temp.name:%p &temp.age:%p &temp.sex:%p &temp.socre:%p\n",&temp,&temp.name,&temp.age,&temp.sex,&temp.socre);
    printf("sizeof(struct test):%lu\n",sizeof(struct test));
}
//结构体数组的应用
void struct_num_2(void)
{
    //定义一个结构体数组
    stu num[2]={
        {"zhangsan",18,11,22,33,44,55},//即使成绩没有花括号括起来也会赋值正确
    {.age=20,.socre[0]=99,.socre[1]=88,.socre[2]=90,.socre[3]=100,.socre[4]=78,.name="wangwu"}};
    show_data(num);
    printf("---\n");
    show_data_bypointer(num);
        printf("---\n");
    //结构体变量之间是可以相互赋值的
    num[1]=b;//b是全局变量  num[1]的姓名就变“b"
      show_data_bypointer(num);
     printf("---\n");

}
//打印数组的数据
void show_data(stu arr[])
{
    int j;
    for(j=0;j<2;j++)
    {
     //访问变量b的成员信息  输出
        printf("姓名：%s,年龄 ：%d ",arr[j].name,arr[j].age);
        printf("成绩：");
        for(int i=0;i<5;i++)
        {
            printf("%.1lf ",arr[j].socre[i]);
        }
        printf("\n");
    }
}
//通过指针的方式来输出 数据
void show_data_bypointer(p_stu p)//这里的p为什么不是*p呢  如果是*p？  因为p_stu就是指针类型  如果*P会变成二级指针
{
    int j;
    printf("%s\n",(*p).name);
    for(j=0;j<2;j++)
    {
     //访问变量b的成员信息  输出p
        printf("姓名：%s,年龄 ：%d ",(*(p+j)).name,(p+j)->age);//两种成员的访问方式  (*(p+j)).name    ；(p+j)->age
        printf("成绩：");
        for(int i=0;i<5;i++)
        {
            printf("%.1lf ",(p+j)->socre[i]);
        }
        printf("\n");
    }
}
//结构体变量的访问
void struct_1(void)
{
      //访问变量b的成员信息  输出
    printf("姓名：%s,年龄 ：%d ",b.name,b.age);
    printf("成绩：");
    for(int i=0;i<5;i++)
    {
        printf("%.1lf ",b.socre[i]);
    }
    printf("\n");
    //定义一个变量初始化赋值
    struct student d={.age=18,.name="lisi",.socre[0]=99,.socre[1]=88,.socre[2]=90,.socre[3]=100,.socre[4]=78};//可以不用按顺序去进行赋值
     printf("姓名：%s,年龄 ：%d ",d.name,d.age);
    printf("成绩：");
    for(int i=0;i<5;i++)
    {
        printf("%.1lf ",d.socre[i]);
    }
    printf("\n");
    //定义一个变量 
    struct student a={0};
    //输入赋值
    printf("请输入姓名:");
   // gets(a.name);
    scanf("%s",a.name);//字符串的数组名 就是首地址
    getchar();//将回车读走
    printf("请输入年龄:");
    scanf("%d",&a.age);
    getchar();
    printf("请输入5科成绩");
     for(int i=0;i<5;i++)
    scanf("%lf",&a.socre[i]);
    printf("姓名：%s,年龄 ：%d ",a.name,a.age);
     printf("成绩：");
    for(int i=0;i<5;i++)
    {
        printf("%.1lf ",a.socre[i]);
    }
}